from EventEngine import EventEngine
from CodeEngine import CodeEngine
from LocationEngine import LocationEngine
from ItemEngine import ItemEngine
from NPCEngine import NPCEngine
from ChatEngine import ChatEngine
from SkillChallengeEngine import SkillChallengeEngine

from ..models import *

class Quest:
    
    event_engine = EventEngine()
    code_engine = CodeEngine()
    location_engine = LocationEngine()
    item_engine = ItemEngine()
    npc_engine = NPCEngine()
    chat_engine = ChatEngine()
    skillchallenge_engine = SkillChallengeEngine()
    
    def put_item_in(self, item, location):
        self.item_engine.create_see_event(item, location)
        self.item_engine.create_pick_event(item, location)
    
    def allow_drop_in(self, item, location):
        self.item_engine.create_drop_event(item, location)
        
    def put_npc_in(self, npc, location):
        self.npc_engine.create_see(npc)
        return self.npc_engine.create_move(npc, location)
    
    def move_npc(self, npc, location):
        return self.npc_engine.create_move(npc, location)
    
    def begin_chat(self, speaker, listener, info):
        speech = self.chat_engine.create_beginning_chat(speaker, listener)
        speech.info = info
        return speech
    
    def end_branch_chat(self, speech):
        branch = self.chat_engine.create_end_branch_chat(speech.speaker, speech.listener)
        branch.info = speech.info + "+"
        speech.branches.add(branch)
        return branch
    
    def branch_chat(self, speech):
        branch = self.chat_engine.create_branch_chat(speech.speaker, speech.listener)
        branch.info = speech.info + "+"
        speech.branches.add(branch)
        return branch
    
    def begin_event(self, speech, precons = []):
        precons.append(self.npc_engine.is_in_same_precon(speech.listener))
        return self.chat_engine.begin_event(speech, precons)
        
    def give_item(self, item, _from, to):
        if to.npc:
            return self.item_engine.create_give_event(item, to)
        else:
            return self.item_engine.create_receive_event(item, _from)
    
    def chain(self, event1, event2):
        event2.preconditions.add(self.code_engine.create_event_precon('Q(id = ' + str(event1.id) + ')'))
    
    def trigger(self, event1, event2):
        event1.actions.add(self.code_engine.create_fire_event_if_ok_action(event2))
        
    def skill_test(self, event, skill, dc):
        test = self.skillchallenge_engine.create_test(skill, dc)
        event.description += '(test : ' + skill.name + ' / ' + str(dc) + ')'
        event.actions.add(self.code_engine.engage_engine_action('global_skillchallenge_engine', event.id, test.id))
        return test

    def skill_challenge(self, name, succ, fail, keywords = None):
        return self.skillchallenge_engine.create_challenge(name, succ, fail, keywords)
    
    def chain_if_success(self, event1, event2, skill_test):
        if event1:
            self.chain(event1, event2)
        event2.preconditions.add(self.code_engine.create_skill_test_precon(skill_test, True))
    
    def chain_if_challenge_success(self, event1, event2, skill_challenge):
        if event1:
            self.chain(event1, event2)
        event2.preconditions.add(self.code_engine.create_skill_challenge_precon(skill_challenge, True))
    
    def chain_if_fail(self, event1, event2, skill_test):
        if event1:
            self.chain(event1, event2)
        event2.preconditions.add(self.code_engine.create_skill_test_precon(skill_test, False))
        
    def chain_if_challenge_fail(self, event1, event2, skill_challenge):
        if event1:
            self.chain(event1, event2)
        event2.preconditions.add(self.code_engine.create_skill_challenge_precon(skill_challenge, False))
        
    def trigger_if_success(self, event1, event2, skill_test):
        if event1:
            self.trigger(event1, event2)
        event2.preconditions.add(self.code_engine.create_skill_test_precon(skill_test, True))
    
    def trigger_if_challenge_success(self, event1, event2, skill_challenge):
        if event1:
            self.trigger(event1, event2)
        event2.preconditions.add(self.code_engine.create_skill_challenge_precon(skill_challenge, True))
        
    def trigger_if_fail(self, event1, event2, skill_test):
        if event1:
            self.trigger(event1, event2)
        event2.preconditions.add(self.code_engine.create_skill_test_precon(skill_test, False))
    
    def trigger_if_challenge_fail(self, event1, event2, skill_challenge):
        if event1:
            self.trigger(event1, event2)
        event2.preconditions.add(self.code_engine.create_skill_challenge_precon(skill_challenge, False))
        
    def new_quest(self, name, reward, keywords=None):
        return QuestModel.objects.create(name=name, keywords=keywords, reward=reward)
    
    def turn_quest_acceptance(self, quest, event):
        event.description += (' (to accept quest ' + str(quest.name) + ')')
        event.save()
        event.actions.add(self.code_engine.engage_engine_action('global_quest_engine', event.id, quest.id))
        quest.engage_actions += str(event.id) + '-ACCEPT:'
        quest.save()
        
    def successful_end(self, quest, event):
        event.actions.add(self.code_engine.engage_engine_action('global_quest_engine', event.id, quest.id))
        quest.engage_actions += str(event.id) + '-SUCCESS:'
        quest.save()
        
    def failure_end(self, quest, event):
        event.actions.add(self.code_engine.engage_engine_action('global_quest_engine', event.id, quest.id))
        quest.engage_actions += str(event.id) + '-FAILURE:'
        quest.save()
    
    def quest_event(self, quest, event, success_condition = None):
        event.preconditions.add(self.code_engine.create_quest_precon(quest, success_condition))
    
    def engage(self, event_id, quest_id, char_id):
        if char_id:
            char = Character.objects.get(id=char_id)
        quest = QuestModel.objects.get(id=quest_id)
        
        actions = {}
        for entry in quest.engage_actions.split(':'):
            if entry:
                actions[int(entry.split('-')[0])] = entry.split('-')[1]
        
        if actions[event_id] == 'ACCEPT':
            quest.holder = char
            quest.save()
        else:
            if actions[event_id] == 'SUCCESS':
                quest.success = True
                quest.holder.score += quest.reward
                quest.holder.save()
                quest.save()
            else:
                if actions[event_id] == 'FAILURE':
                    quest.failed = True
                    quest.save()